﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Biosek.Formats.UniProt;

namespace Biosek
{
	public static class UniprotHelper
	{
		/// <summary>
		/// obtiene todos los accessiones asociados a un entry como una cadena de texto separados por coma y espacio
		/// </summary>
		public static string GetAccessionsString(this entry entry)
		{
			if (entry == null) return string.Empty;
			var r = string.Join(", ", entry.accession);
			return r;
		}

		public static bool AreConsecutive(featureType f1, featureType f2)
		{
			return f1.GetLastLocation() + 1 == f2.GetFirstLocation();
		}

		static Dictionary<char, byte> AminoacidToByte;

		/// <summary>
		/// Intepreta una cadena de aminoacidos en modo texto convirtiendola en un array de bytes
		/// </summary>
		public static byte[] TranslateAminoacidStringToByteString(string str)
		{
			if (AminoacidToByte == null)
			{
				AminoacidToByte = new Dictionary<char, byte>();
				for (char i = 'A'; i <= 'Z'; i++) AminoacidToByte[i] = (byte)(i - 'A');
				for (char i = 'a'; i <= 'z'; i++) AminoacidToByte[i] = (byte)(i - 'a');
			}
			var res = str.Select(x => AminoacidToByte[x]).ToArray();
			return res;
		}

		/// <summary>
		/// Obtiene la secuencia transoformando simbolos de aminoacido en bytes
		/// </summary>
		public static byte[] GetPartialSequenceAsByteString(this entry entry, int startOffset, int length)
		{
			var r = entry.GetPartialSequence(startOffset, length);
			var res = TranslateAminoacidStringToByteString(r);
			return res;
		}

		/// <summary>
		/// Obtiene la secuencia transoformando simbolos de aminoacido en bytes
		/// </summary>
		public static byte[] GetSequenceAsByteString(this entry entry)
		{
			var res = entry.GetPartialSequenceAsByteString(0, entry.GetSequence().Length);
			return res;
		}

		/// <summary>
		/// Obtiene las locaciones como una cadena texto separados por coma y espacio
		/// </summary>
		public static string GetLocationsString(this featureType feature)
		{
			if (feature == null || feature.location == null || feature.location.Items == null) return string.Empty;
			var locs = feature.location.Items.Select(x => x.position.ToString());
			var r = string.Join(", ", locs);
			return r;
		}

		/// <summary>
		/// Obtiene los chains
		/// </summary>		
		public static IEnumerable<featureType> GetChains(this entry entry)
		{
			if (entry == null || entry.feature == null) return Enumerable.Empty<featureType>();
			return entry.feature.Where(x => x.type == featureTypeType.chain);
		}

		/// <summary>
		/// Obtiene la cadena del indice especificado
		/// </summary>		
		public static featureType GetChain(this entry entry, int chainIndex)
		{
			return GetChains(entry).Skip(chainIndex).FirstOrDefault();
		}

		/// <summary>
		/// Obtiene la primera locacion de la caracteristica.
		/// Fallara si no contiene esta informacion. 
		/// La locacion se devuelve tal como esta en el archivo de UniProt es decir
		/// como indice basado en 1.
		/// </summary>
		public static int GetFirstLocation(this featureType feature)
		{
			var loc = (int)feature.location.Items.First().position;
			return loc;
		}

		/// <summary>
		/// Obtiene la ultima locacion de la caracteristica. 
		/// Fallara si no contiene esta informacion
		/// La locacion se devuelve tal como esta en el archivo de UniProt es decir
		/// como indice basado en 1.
		/// </summary>
		public static int GetLastLocation(this featureType feature)
		{
			var loc = (int)feature.location.Items.Last().position;
			return loc;
		}

		/// <summary>
		/// Obtiene la longitud en simbolos de la seccion de la caracteristica especificada
		/// </summary>		
		public static int GetFeatureLength(this featureType feature)
		{
			var i = feature.GetFirstLocation();
			var e = feature.GetLastLocation();
			return e - i + 1;
		}

		/// <summary>
		/// Obtiene los chains
		/// </summary>		
		public static IEnumerable<featureType> GetSites(this entry entry)
		{
			if (entry.feature == null) return Enumerable.Empty<featureType>();
			return entry.feature.Where(x => x.type == featureTypeType.site);
		}

		/// <summary>
		/// Obtiene la cadena de la secuencia para esta entrada en un archivo uniprot. Filtering whitespaces
		/// </summary>		
		public static string GetSequence(this entry uniprotEntry)
		{
			var seq = uniprotEntry.sequence.Value;
			var sb = new StringBuilder(seq.Length);
			foreach (var item in seq)
			{
				if (char.IsLetter(item)) sb.Append(item);
			}
			return sb.ToString();
		}

		public static string GetPartialSequence(this entry uniprotEntry, int startOffset, int length)
		{
			return GetSequence(uniprotEntry).Substring(startOffset, length);
		}

		/// <summary>
		/// Obtiene la secuencia del chain indicado como cadena de texto
		/// </summary>
		public static string GetChainSequence(this entry uniprotEntry, int chainIndex)
		{
			var chain = GetChain(uniprotEntry, chainIndex);
			return GetSequence(uniprotEntry).Substring(chain.GetFirstLocation() - 1, chain.GetFeatureLength());
		}
	}
}
